import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class VendingMachineTest {
	
	VendingMachine myVendingMachine;
	VendingMachineItem snickers;
	VendingMachineItem sprite;
	

	@Before
	public void setUp() throws Exception {
		myVendingMachine = new VendingMachine();
		snickers = new VendingMachineItem("snickers", 1.00);
		sprite = new VendingMachineItem("sprite", 1.25);
		
	}

	@After
	public void tearDown() throws Exception {
	}

	/* 
	 * Test case 1 will add an item in empty slot A
	 * 
	 */
	
	@Test
	public void testAddItem_Case1() {
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		assertEquals(snickers, myVendingMachine.getItem(VendingMachine.A_CODE));
	}
	
	/* 
	 * Test case 2 will add an item in empty slot B
	 * 
	 */
	
	@Test
	public void testAddItem_Case2() {
		myVendingMachine.addItem(sprite, VendingMachine.B_CODE);
		assertEquals(sprite, myVendingMachine.getItem(VendingMachine.B_CODE));
	}
	
	/* 
	 * Test case 3 will add an item in empty slot C
	 * 
	 */
	
	@Test
	public void testAddItem_Case3() {
		myVendingMachine.addItem(snickers, VendingMachine.C_CODE);
		assertEquals(snickers, myVendingMachine.getItem(VendingMachine.C_CODE));
	}
	
	/* 
	 * Test case 4 will add an item in empty slot D
	 * 
	 */
	
	@Test
	public void testAddItem_Case4() {
		myVendingMachine.addItem(sprite, VendingMachine.D_CODE);
		assertEquals(sprite, myVendingMachine.getItem(VendingMachine.D_CODE));
	}
	
	/* 
	 * Test case 5 will throw an exception if adding valid item to invalid slot
	 * 
	 */
	
	@Test (expected=VendingMachineException.class) 
	public void testAddItem_case5() throws Exception {
		myVendingMachine.addItem(snickers, "E");
	}

	
	/* 
	 * Test case 6 will throw an exception if adding valid item to a null slot
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testAddItem_case6() throws Exception {
		myVendingMachine.addItem(snickers, null);
	}
	
	/* 
	 * Test case 7 will throw an exception if adding invalid item to a valid slot
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testAddItem_Case7() throws Exception{
		myVendingMachine.addItem(null, myVendingMachine.A_CODE);
	}
	
	/* 
	 * Test case 8 will throw an exception if adding 2 items to one slot
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testAddItem_Case8()throws Exception {
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		myVendingMachine.addItem(sprite, VendingMachine.A_CODE);
	}

	/* 
	 * Test case 9 make sure if an item was added to slot A than that same item is dispensed
	 * 
	 */
	
	@Test
	public void testRemoveItem_Case9() {
			myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
			assertEquals(snickers, myVendingMachine.removeItem(VendingMachine.A_CODE));
	}

	/* 
	 * Test case 10 make sure if an item was added to slot B than that same item is dispensed
	 * 
	 */
	
	@Test
	public void testRemoveItem_Case10() {
			myVendingMachine.addItem(sprite, VendingMachine.B_CODE);
			assertEquals(sprite, myVendingMachine.removeItem(VendingMachine.B_CODE));
	}
	
	/* 
	 * Test case 11 make sure if an item was added to slot C than that same item is dispensed
	 * 
	 */
	
	@Test
	public void testRemoveItem_Case11() {
			myVendingMachine.addItem(snickers, VendingMachine.C_CODE);
			assertEquals(snickers, myVendingMachine.removeItem(VendingMachine.C_CODE));
	}
	
	/* 
	 * Test case 12 make sure if an item was added to slot D than that same item is dispensed
	 * 
	 */
	
	@Test
	public void testRemoveItem_Case12() {
			myVendingMachine.addItem(sprite, VendingMachine.D_CODE);
			assertEquals(sprite, myVendingMachine.removeItem(VendingMachine.D_CODE));
	}
	
	/* 
	 * Test case 13 will throw an exception of an item is being removed from an invalid spot
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testRemoveItem_Case13() {
		myVendingMachine.removeItem("Y");
	}
	
	/* 
	 * Test case 14 will remove a valid item from slot A
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testRemoveItem_Case14() {
		myVendingMachine.removeItem(VendingMachine.A_CODE);
	}
	
	/* 
	 * Test case 15 will test if correct amount was inserted then item dispensed 
	 * 
	 */
	
	@Test
	public void testInsertMoney_Case15() {
		myVendingMachine.insertMoney(1.00);
		assertEquals(1.00, myVendingMachine.getBalance(), 0.00);
	}
	
	/* 
	 * Test case 16 will throw exception if negative amount was entered 
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testInsertMoney_Case16() {
		myVendingMachine.insertMoney(-1.00);
		
	}
	
	/* 
	 * Test case 17 will accept even if no amount entered 
	 * 
	 */
	
	@Test
	public void testInsertMoney_Case17() {
		myVendingMachine.insertMoney(0.00);
		assertEquals(0.00, myVendingMachine.getBalance(), 0.00);
		
	}

	/* 
	 * Test case 18 gets balance starting at $0
	 * 
	 */
	
	@Test
	public void testGetBalance_Case18() {
		assertEquals(0.00, myVendingMachine.getBalance(), 0.00);
	}
	
	/* 
	 * Test case 19 will accept bills that are entered
	 * 
	 */
	
	@Test
	public void testGetBalance_Case19() {
		myVendingMachine.insertMoney(5.00);
		assertEquals(5.00, myVendingMachine.getBalance(), 0.00);
	}
		
	/* 
	 * Test case 20 will accept bills and change that are entered
	 * 
	 */
	
	@Test
	public void testGetBalance_Case20() {
		myVendingMachine.insertMoney(5.00);
		myVendingMachine.insertMoney(0.50);
		assertEquals(5.50, myVendingMachine.getBalance(), 0.00);
	}
	
	/* 
	 * Test case 21 will get balance once money is inserted, item is added, and item is purchased
	 * 
	 */
	
	@Test
	public void testGetBalance_Case21() {
		myVendingMachine.insertMoney(5.00);
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		myVendingMachine.makePurchase(VendingMachine.A_CODE);
		assertEquals(4.00, myVendingMachine.getBalance(), 0.00);
	}

	/* 
	 * Test case 22 will test to make sure its false when no amount is added
	 * 
	 */
	
	@Test
	public void testMakePurchase_Case22() {
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		assertFalse(myVendingMachine.makePurchase(VendingMachine.A_CODE));
	}

	/* 
	 * Test case 23 will test to make sure if low amount is added 
	 * 
	 */
	
	@Test
	public void testMakePurchase_Case23() {
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		myVendingMachine.insertMoney(0.25);
		assertFalse(myVendingMachine.makePurchase(VendingMachine.A_CODE));
	}
	
	/* 
	 * Test case 24 will make sure if the correct amount is added then that item will be dispensed 
	 * 
	 */
	
	@Test
	public void testMakePurchase_Case24() {
		myVendingMachine.addItem(sprite, VendingMachine.A_CODE);
		myVendingMachine.insertMoney(1.25);
		assertTrue(myVendingMachine.makePurchase(VendingMachine.A_CODE));
	}
	
	/* 
	 * Test case 25 will throw an exception even if correct amount because its an invalid spot 
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testMakePurchase_Case25() {
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		myVendingMachine.insertMoney(1.00);
		myVendingMachine.makePurchase("F");
	}
	
	/* 
	 * Test case 26 will throw an exception even its the correct amount because the slot is empty 
	 * 
	 */
	
	@Test(expected = VendingMachineException.class)
	public void testMakePurchase_Case26() {
		myVendingMachine.insertMoney(1.25);
		assertFalse(myVendingMachine.makePurchase(VendingMachine.A_CODE));
	}
	
	/* 
	 * Test case 27 will start by accepting $0 
	 * 
	 */
	
	@Test
	public void testReturnChange_Case27() {
		assertEquals(0.00, myVendingMachine.returnChange(), 0.00);
	}

	/* 
	 * Test case 28 will return the correct change after item was added and over payment was added 
	 * 
	 */
	
	@Test
	public void testReturnChange_Case28() {
		myVendingMachine.addItem(snickers, VendingMachine.A_CODE);
		myVendingMachine.insertMoney(1.50);
		myVendingMachine.makePurchase(VendingMachine.A_CODE);
		assertEquals(0.50, myVendingMachine.returnChange(), 0.00);
	}
	
	/* 
	 * Test case 29 will test if correct amount added, no change will be returned  
	 * 
	 */
	
	@Test
	public void testReturnChange_Case29() {
		myVendingMachine.addItem(sprite, VendingMachine.A_CODE);
		myVendingMachine.insertMoney(1.25);
		myVendingMachine.makePurchase(VendingMachine.A_CODE);
		myVendingMachine.returnChange();
		assertEquals(0.00, myVendingMachine.returnChange(), 0.00);
	}
	/* 
	 * Test case 30 will test if correct amount added, but nothing added then will return the change  
	 * 
	 */
	
	@Test
	public void testReturnChange_Case30() {
		myVendingMachine.addItem(sprite, VendingMachine.A_CODE);
		myVendingMachine.insertMoney(1.25);
		myVendingMachine.returnChange();
		assertEquals(0.00, myVendingMachine.getBalance(), 0.00);
	}
}
